package cz.muni.fi.pa165.languageschool;

import cz.muni.fi.pa165.languageschool.utils.DayOfWeek;
import java.io.Serializable;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 * Entity representing Lecture
 *
 * @author Michal Fučík (395624) michal.fuca.fucik(at)gmail.com
 */
@Entity
@Table(name = "Lecture")
@XmlRootElement
public class Lecture implements Comparable<Lecture>, Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Lecture_id")
    private Long id;
    private String label;
    private String topicDescription;

    @ManyToOne
    private Course course;

    @ManyToOne
    private Lecturer lecturer;

    @ManyToMany(mappedBy = "enrolledLectures", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<Student> enrolledStudents = new ArrayList();
    @Temporal(TemporalType.TIME)
    private Date tpTime;
    private DayOfWeek tpDay;

    // -- Methods --------------------------------------------------------------
    /**
     * Enrolled students property getter
     *
     * @return enrolled students list
     */
    @XmlTransient
    public List<Student> getEnrolledStudents() {
        return enrolledStudents;
    }

    /**
     * Enrolled students property setter
     *
     * @param enrolledStudents
     */
    public void setEnrolledStudents(List<Student> enrolledStudents) {
        if (enrolledStudents != null) {
            for (Student s : enrolledStudents) {
                enroll(s);
            }
        }
    }

    /**
     * Adds student into enrolled students list and sets up appropriate property
     * in student
     *
     * @param s
     */
    public void enroll(Student s) {
        this.enrolledStudents.add(s);
        if (s != null && !s.getEnrolledLectures().contains(this)) {
            s.getEnrolledLectures().add(this);
        }
    }

    /**
     * Makes disenroll with editing of appropriate Student's property
     *
     * @param s
     */
    public void disenroll(Student s) {
        this.enrolledStudents.remove(s);
        if (s != null && s.getEnrolledLectures().contains(this)) {
            s.getEnrolledLectures().remove(this);
        }
    }

    /**
     * Lecturer property getter
     *
     * @return
     */
    public Lecturer getLecturer() {
        return lecturer;
    }

    /**
     * Lecturer property setter
     *
     * @param lecturer
     */
    public void setLecturer(Lecturer lecturer) {
        this.lecturer = lecturer;
        if (lecturer != null && !lecturer.getLectures().contains(this)) {
            lecturer.addLecture(this);
        }
    }

    /**
     * TopicDescription property getter
     *
     * @return
     */
    public String getTopicDescription() {
        return topicDescription;
    }

    /**
     * TopicDescription property setter
     *
     * @param topicDescription
     */
    public void setTopicDescription(String topicDescription) {
        this.topicDescription = topicDescription;
    }

    /**
     * TpTime property getter
     *
     * @return SQL Time
     */
    public Time getTpTime() {
        if (this.tpTime != null) {
            return new Time(tpTime.getTime());
        }
        return null;
    }

    /**
     * TpTime property setter
     *
     * @param tpTime of taking place
     */
    public void setTpTime(Time tpTime) {
        if (tpTime == null) {
            this.tpTime = null;
        } else {
            this.tpTime = new Date(tpTime.getTime());
        }
    }

    /**
     * TpDay property getter
     *
     * @return DayofWeek representation of taking place
     */
    public DayOfWeek getTpDay() {
        return tpDay;
    }

    /**
     * TpDay property setter
     *
     * @param tpDay
     */
    public void setTpDay(DayOfWeek tpDay) {
        this.tpDay = tpDay;
    }

    /**
     * Id property setter
     *
     * @param id
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * Id property getter
     *
     * @return
     */
    public Long getId() {
        return id;
    }

    /**
     * Course property getter
     *
     * @return
     */
    public Course getCourse() {
        return course;
    }

    /**
     * Course property setter (updates Courses related lectures list)
     *
     * @param course
     */
    public void setCourse(Course course) {
        this.course = course;
        if (course != null && !course.getRelatedLectures().contains(this)) {
            course.addLecture(this);
        }
    }

    /**
     * Label property getter
     *
     * @return Lecture label
     */
    public String getLabel() {
        return label;
    }

    /**
     * Label property setter
     *
     * @param name
     */
    public void setLabel(String name) {
        this.label = name;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += 7 * (getId() != null ? this.getId().hashCode() : 0);
        hash += 7 * getLabel().hashCode();
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Lecture other = (Lecture) obj;
        if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
            return false;
        }
        if ((this.label == null) ? (other.label != null) : !this.label.equals(other.label)) {
            return false;
        }
        return true;
    }

    @Override
    public int compareTo(Lecture lec) {
        if (lec == null) {
            throw new NullPointerException("Argument lec was null");
        }

        if (getId() == null) {
            if (getLabel() != null) {
                return getLabel().compareToIgnoreCase(lec.getLabel());
            }
        }
        return getId().compareTo(lec.getId());
    }
}
